Унаследовано от "gitlab.systems-fd.com/packages/golang/servers/msrc/v3

# Библиотека мультисервисного приложения для `Golang`

Библиотека предназначена для реализации мультисервисных приложений на `Golang`.
Например: У вас есть сервис, который предоставляет RestAPI, а также требуется реализация
Websocket. По сути каждый сервис требует блокировки основной `Go-routine`, можно использовать
дочерние `go-routine`, что по сути и делает эта библиотека.
Также библиотека реализует `Graceful shutdown`, который позволит правильно останавливать сервисы.
Сервис поддерживает логирование на основе `github.com/sirupsen/logrus`

## Установка

Необходимо включить библиотеку в один из скриптов следующим образом:
```go
import "gitlab.systems-fd.com/packages/golang/servers/msrc/v3"
```

Далее необходимо установить зависимости при помощи стандартной утилиты `go get`:
```bash
go get -u gitlab.systems-fd.com/packages/golang/servers/msrc/v3
```
                  
## Использование

Для использования библиотеки необходимо реализовать интерфейс сервиса:
```go
// ServiceInterface описывает интерфейс сервиса, для параллельного запуска.
type ServiceInterface interface {
	// Run выполняет запуск сервера
	Run() error

	// GracefulShutdown выполняет правильную остановку сервиса
	GracefulShutdown()

	// IsStarted возвращает статус состояния запуска сервиса
	IsStarted() bool

	// IsAlive возвращает статус сервиса: живой или нет
	IsAlive() bool
}
```

Далее необходимо использовать фабрику для генерации объекта службы:
```go
service := msrc.MultiService(
    map[string]multiservice.ServiceInterface{
        "Test-Service": &service{},
    },
)
```

При передаче списка, ключ используется в качестве уникального названия сервиса.

После создания объекта сервиса необходимо его запустить:
```go
err := service.Run()
```

В случае возникновения ошибки сервис остановит все подсервисы с использованием `Graceful shutdown`
и вернет возникшую ошибку.

## Укороченный интерфейс сервиса

В библиотеку включена реализация функционала отслеживания статуса остановки и завершения
на основе контекста. Данный функционал входит в реализацию `msrc.SimpleService`

Данный сервис принимает на вход сервис с интерфейсом:
```go
// SimpleService описывает интерфейс упрощенного сервиса, для библиотеки.
// Данный сервис может быть использован в случаях, когда нет необходимости
// внутри следить за флагами состояния. Сервис должен реализовывать лишь
// функционал работы и правильной остановки.
type SimpleService interface {
	// Run выполняет запуск упрощенной версии сервиса.
	// На вход передается контекст, который передаст `<-ctx.Done()` в случае
	// его остановки. Сам сервис должен обрабатывать его, если он не реализует
	// своего собственного, отдельного алгоритма остановки.
	Run(ctx context.Context) error

	// GracefulShutdown выполняет правильную остановку упрощенного
	// сервиса. В данном случае, если сервис необходимо останавливать
	// вызовом отдельного функционала остановки, этот метод предоставляет
	// такую возможность.
	//
	// Метод вызывается в процессе остановки сервера и принимает на вход
	// контекст с deadline, устанавливаемым сверху. За установленное время
	// сервис либо завершает работу, либо отключается принудительно.
	GracefulShutdown(ctx context.Context) error
}
```

Для превращения его в полноценный сервис необходимо использовать функцию `msrc.SimpleService`.
Она обернет такой сервис в стандартную реализацию, которая позволит отслеживать Liveness Probe
на основе статуса работы сервиса, а так же останавливать его при помощи встроенного контекста,
который будет переключаться на `<-ctx.Done()` при завершении работы.

Данный функционал позволяет так же реализовывать правильную остановку, если ваш сервис не поддерживает
остановку через контекст.

В качестве последнего аргумента можно передать таймаут ожидания завершения работы функции.
Логика работы следующая: либо сервис завершает работу за это время, либо разблокируем остановку,
чтоб не ожидать дольше положенного времени. По умолчанию данный интервал ожидания - 5 секунд.

Если передать в качестве интервала ожидания 0, то таймаут ожидания составит 1000 часов, что
по сути эквивалентно ожиданию реальной остановки сервиса.

## HTTP сервер

В библиотеку включена поставка стандартного HTTP сервера в виде обертки для Multi Service.
Данная обертка принимает на вход хост и порт для HTTP сервера, а так же роутер, который
необходимо использовать для сервера. Роутер должен реализовывать стандартный интерфейс
`http.Handler`.

Данный сервис так же позволяет переопределять стандартные параметры сервера. Для этого
необходимо передать переопределение в качестве последнего аргумента фабрики.

```go
// HttpService реализует фабрику сервиса для библиотеки, реализующего
// функционал HTTP сервера. На вход передаются обязательные аргументы
// для HTTP сервера, а так же возможна передача конфигурации запуска
// сервера.
//
// Если конфигурация запуска не передана, то будет использоваться конфигурация
// `http.Server{}`, при этом в обоих случаях (передано/не передано) будет
// происходить переопределение полей Addr и Handler в соответствии с
// переданными обязательными аргументами функции.
func HttpService(
	HttpHost, HttpPort string,
	Router http.Handler,
	GraceStopPeriodSeconds uint8,
	ServerConfig ...*http.Server,
) ServiceInterface
```

## Реализация Liveness для Kubernetes

Для реализации данного функционала у каждого сервиса предусмотрено 2 метода:
```go
// Возвращает статус состояния запуска сервиса
IsStarted() bool

// Возвращает статус сервиса: живой или нет
IsAlive() bool
```

Первый возвращает статус **запуска сервера**. Используется для `Readyness Probe`

Второй возвращает статус: **жив ли сервис**. Используется для `Liveness Probe`

По сути статусы всех сервисов суммируются и выдается итоговый результат как для `readyness`,
так и для `liveness`, поэтому если хотябы один сервис умрет, то `liveness` не пройдут и будет
вызвана остановка пода.

Для настройки Kubernetes необходимо при инициализации сервиса передать порт прослушивания liveness:
```go
service := multiservice.MultiService(
    map[string]multiservice.ServiceInterface{
        "Test-Service": &service{},
    },
    19000
)
```

Если передано значение 0, то liveness не будет подключен. По умолчанию данный аргумент можно не передавать.

Для проверки используйте следующие url контейнера:
```
/ready - Readyness Probe
/alive - Liveness Probe
```